Swift Tutorial | Simple UITableView with RxSwift and RxCocoa

RxSwift is awesome we know it and most of us have experienced it. We also know that it is very easy to learn but requires a different thought process making it a bit tough to wrap your head around it. In this post, we will be making a simple UITableView implementation using RxSwift and RxCocoa. No complex patterns to confuse you, the idea is to understand one thing at a time. If you are looking for without Rx implementation you can have a look here..

Getting started

  • Create a project you can name it as per your choice select Storyboard
  • Close xcode project
  • Open terminal and cd <your project folder>
  • Run pod init
  • Run pod install
  • Open your project from workspace file. Pod install will create a workspace file for you its almost always below your pbxproject file
  • In the project you will see Pods folder expand it and open pod file it will look some thing like this
UITableView with RxSwift
  • Add pods for RxSwift and RxCocoa
    •   pod ‘RxSwift’, ‘~> 5’
    •   pod ‘RxCocoa’, ‘~> 5’
  • Close the project again and run pod install in terminal

Setting up your UITableView

  • Drop a UITableView in ViewController Scene of your stroy borad and set constraints 0,0,0,0
  • Add a UITableViewCell in the table view and set its Identifier as “Cell”
  • Create a     @IBOutlet weak var tableView:UITableView! and link your table view

Setting up your view controller

Start by importing RxSwift and RxCocoa in your view controller.

import RxCocoa
import RxSwift

Create a dispose bag and data source

    var fruitDic: BehaviorRelay<[[String : String]]> =
          BehaviorRelay(value:
              [["name":"apple"],
               ["name":"banana"],
               ["name":"cherries"],
               ["name":"grapes"],
               ["name":"lemon"],
               ["name":"orange"],
               ["name":"strawberry"],
               ["name":"tomato"]])
      
      var disposeBag = DisposeBag()

In order to create our data source, we have used behaviour relay. It stores values that cannot be mutated. In order to change the data stored in a BehaviourRelay we must first extract it and update it after that we can put it back in BehaviourRelay. BehaviourRelay emits the latest data it has to all its subscribers. We need to subscribe to our data source but before that, we will setup tableview delegate

      func inputTableView() {
          
          // Set tableview delegate. 
        tableView.rx
              .setDelegate(self)
              .disposed(by: disposeBag)
          
          // Bind fruit dictionary and tableview
          fruitDic.asObservable()
              .bind(to: tableView.rx
                        .items(cellIdentifier: "Cell", cellType: UITableViewCell.self))
              { index, element, cell in
                  // Write image, name for cell label.
                cell.textLabel?.text = element["name"]
          }.disposed(by: disposeBag)

        tableView.tableFooterView = UIView()
    }

Now call this function inputTableView() from your viewDidLoad and add the table view delegate method for row height. After this, you can run your project in the simulator to see the table view working. I have also added item selected subscription and the final Viewcontroller class looks like this.

 //
//  ViewController.swift
//  RxSwiftUItableview
//
//  Created by amarendra on 10/09/21.
//

import UIKit
import RxCocoa
import RxSwift

class ViewController: UIViewController, UITableViewDelegate {

    @IBOutlet weak var tableView:UITableView!
    var fruitDic: BehaviorRelay<[[String : String]]> =
          BehaviorRelay(value:
              [["name":"apple"],
               ["name":"banana"],
               ["name":"cherries"],
               ["name":"grapes"],
               ["name":"lemon"],
               ["name":"orange"],
               ["name":"strawberry"],
               ["name":"tomato"]])
      
      var disposeBag = DisposeBag()
      
      override func viewDidLoad() {
          super.viewDidLoad()
          inputTableView()
      }
      
      
      func inputTableView() {
          
          // Set tableview delegate. 
        tableView.rx
              .setDelegate(self)
              .disposed(by: disposeBag)
          
          // Bind fruit dictionary and tableview
          fruitDic.asObservable()
              .bind(to: tableView.rx
                        .items(cellIdentifier: "Cell", cellType: UITableViewCell.self))
              { index, element, cell in
                  // Write image, name for cell label.
                cell.textLabel?.text = element["name"]
          }.disposed(by: disposeBag)
        // added did select equivalent and printed corresponding name 
        tableView.rx.itemSelected.subscribe { [weak self] (indexPath) in
            print(self!.fruitDic.value[indexPath.row]["name"]!)
        }.disposed(by: disposeBag)
          
        tableView.tableFooterView = UIView()
      }
       
    
      func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
          return 40
      }

}
A pat on the back !!